
#include <binary_iarchive.hpp>
#include <binary_oarchive.hpp>
#include <cassert>

template<typename T>
void advance(T *obj)		// default for integer
{
	*obj += 9;
}

template<>
void advance(std::string *str)
{
	(*str) += "_abcdef_\n";
}

template<>
void advance(std::vector<std::string> *vec)
{
	vec->push_back("_abcdef_\n");
}

struct userT
{
	std::string name;
	int age;
	std::vector<std::string> friends;

	userT()
		: name("")
		, age(0)
		, friends() {}

	bool operator==(const userT &other) const {
		return (name == other.name)
			&& (age == other.age)
			&& (friends == other.friends);
	}

	template<typename IArchive>
	bool load(IArchive &in) {
		in >> name >> age >> friends;
		return in.good();
	}

	template<typename OArchive>
	bool save(OArchive &out) const {
		out << name << age << friends;
		return out.good();
		//return out.save(name) && out.save(age) && out.save(friends);
	}
};

template<>
void advance(userT *obj)
{
	obj->age += 10;
	obj->friends.push_back("_abcdef_\n");
	obj->name += '!';
}

struct config
{
	static const bool disable_all = false;
	static const bool enable_check_data_bound = true;
	static const bool enable_check_size_limits = true;
};

template<typename T>
void test_T()
{
	T obj = T();
	char buf[1024];
	const int times = 10;

	kb::binary_oarchive<kb::network_byteorder, config> out(buf, sizeof(buf));

	assert(out.left_buffer_size() == sizeof(buf));
	assert(out.used_buffer_size() == 0);

	for(int i=0; i<times && out.good(); ++i)
	{
		out << obj;
		advance(&obj);
	}

	assert(out.empty() == false);
	assert(out.good());
	assert(out.fail() == false);

	kb::binary_iarchive<kb::network_byteorder> in(out.used_buffer(),
						      out.used_buffer_size());

	assert(in.left_buffer_size() == out.used_buffer_size());
	assert(in.used_buffer_size() == 0);
	
	T obj_orignal = T();
	T obj_got = T();
	for(int i=0; i<times && in.good(); ++i)
	{
		in >> obj_got;
		assert(in.good());
		assert(obj_got == obj_orignal);
		advance(&obj_orignal);
	}
	
	assert(in.empty() == true);
	assert(in.good());
	assert(in.fail() == false);
}

int main()
{
	test_T<int8_t>();
	test_T<uint16_t>();
	test_T<uint32_t>();
	test_T<int64_t>();
	test_T<std::string>();
	test_T<std::vector<std::string> >();
	test_T<userT>();
	
	return 0;
}
